#include "redis.hpp"

Redis::Redis()
   :_publish(nullptr)
   ,_subscribe(nullptr)
{
}

Redis::~Redis()
{
    if (_publish != nullptr)
        redisFree(_publish);

    if (_subscribe != nullptr)
        redisFree(_subscribe);
}
// 连接redis缓存
bool Redis::connect()
{
    // redis服务器启动后默认的端口号是6379;
    _publish = redisConnect("127.0.0.1", 6379);

    if (_publish == nullptr)
    {
        std::cerr << "redis connect failed" << std::endl;
        return false;
    }

    _subscribe = redisConnect("127.0.0.1", 6379);
    if (_subscribe == nullptr)
    {
        std::cerr << "redis connect failed" << std::endl;
        return false;
    }

    // 创建唯一的负责接受的线程,然后设置分离线程
    std::thread t([&]()
                  { observer_receive_message(); });
    t.detach();

    std::cout << "redis connect sucessful" << std::endl;

    return true;
}
// 对于链接后的操作
bool Redis::subscribe(int channel)
{
    // 构建命令
    if (REDIS_ERR == redisAppendCommand(_subscribe, "subscribe %d", channel))
    {
        std::cerr << "redis subscribe set failed" << std::endl;
        return false;
    }

    // 将命令发送给redis服务器
    int write = 0;
    while (!write)
    {
        if (REDIS_ERR == redisBufferWrite(_subscribe, &write))
        {
            std::cerr << "send redis subscribe to server of redis failed" << std::endl;
            return false;
        }
    }

    std::cout << "redis subscribe set sucessful" << std::endl;
    // redisgetreply(这就是阻塞接受消息的)
    return true;
}

bool Redis::unsubscribe(int channel)
{
   // 构建命令
    if (REDIS_ERR == redisAppendCommand(_subscribe, "unsubscribe %d", channel))
    {
        std::cerr << "redis unsubscribe set failed" << std::endl;
        return false;
    }

    // 将命令发送给redis服务器
    int write = 0;
    while (!write)
    {
        if (REDIS_ERR == redisBufferWrite(_subscribe, &write))
        {
            std::cerr << "send redis unsubscribe to server of redis failed" << std::endl;
            return false;
        }
    }

    std::cout << "redis unsubscribe set sucessful" << std::endl;
    // redisgetreply(这就是阻塞接受消息的)
    return true;

}


bool Redis::publish(int channel, std::string message)
{
    redisReply *reply = (redisReply *)redisCommand(_publish, "publish %d %s", channel, message.c_str());
    if (reply == nullptr)
    {
        std::cerr << "redis publish " << channel << " " << message << "failed" << std::endl;
        freeReplyObject(reply);

        return false;
    }

    freeReplyObject(reply);
    std::cout << "redis publish " << channel << " " << message << "sucessful" << std::endl;

    return true;
}

// 在独立线程中查看信息，因为redis接受信息是阻塞的，所以必须单开一个线程查看信息
void Redis::observer_receive_message()
{
    redisReply *reply = nullptr;
    // 这就是一个阻塞的，永久的死循环
    while (REDIS_OK == redisGetReply(_subscribe, (void **)&reply))
    {
        //再未来呢，没当这个线程接收到了信息，这里都会进行一次调用，就形成了自动调用的现象
        if (reply != nullptr && reply->element[1] != nullptr && reply->element[2] != nullptr)
            _initNotifyHandler(atoi(reply->element[1]->str), reply->element[2]->str);

        //这里的释放是正确的，每一次把redisGetReply的老数据释放掉，不会影响下一次使用（因为reply一开始就是空指针）
        if (reply != nullptr)
            freeReplyObject(reply);
    }

    std::cerr << "error observer_recvice_messgae quit" << std::endl;
}
// 注册回调函数接收消息(所以这个参数应该得是一个函数对象)
void Redis::init_notify_handler(std::function<void(int, std::string)> fn)
{
    // 正式注册回调函数，方便以后调用
    this->_initNotifyHandler = fn;
}